package Question5_3;
public class Question {
public static int countOnes(int i) {
int count = 0;
while (i > 0) {
if ((i & 1) == 1) {
count++;
}
i = i >> 1;
}
return count;
}
public static int countZeros(int i) {
return 32 - countOnes(i);
}
public static boolean hasValidNext(int i) {
if (i == 0) {
return false;
}
int count = 0;
while ((i & 1) == 0) {
i >>= 1;
count++;
}
while ((i & 1) == 1) {
i >>= 1;
count++;
}
if (count == 31) {
return false;
}
return true;
}
public static boolean hasValidPrev(int i) {
while ((i & 1) == 1) {
i >>= 1;
}
if (i == 0) {
return false;
}
return true;
}
public static int getNextSlow(int i) {
if (!hasValidNext(i)) {
return -1;
}
int num_ones = countOnes(i);
i++;
while (countOnes(i) != num_ones) {
i++;
}
return i;
}
public static int getPrevSlow(int i) {
if (!hasValidPrev(i)) {
return -1;
}
int num_ones = countOnes(i);
i--;
while (countOnes(i) != num_ones) {
i--;
}
return i;
}
public static int getNext(int n) {
int c = n;
int c0 = 0;
int c1 = 0;
while (((c & 1) == 0) && (c != 0)) {
c0++;
c >>= 1;
}
while ((c & 1) == 1) {
c1++;
c >>= 1;
}
/* If c is 0, then n is a sequence of 1s followed by a sequence of 0s. This is already the biggest
* number with c1 ones. Return error.
*/
if (c0 + c1 == 31 || c0 + c1 == 0) {
return -1;
}
int pos = c0 + c1; // position of right-most non-trailing zero (where the right most bit is bit 0)
/* Flip the right-most non-trailing zero (which will be at position pos) */
n |= (1 << pos); // Flip right-most non-trailing zero
/* Clear all bits to the right of pos.
* Example with pos = 5
* (1) Shift 1 over by 5 to create 0..0100000 [ mask = 1 << pos ]
* (2) Subtract 1 to get 0..0011111 [ mask = mask - 1 ]
* (3) Flip all the bits by using '~' to get 1..1100000 [ mask = ~mask ]
* (4) AND with n
*/
n &= ~((1 << pos) - 1); // Clear all bits to the right of pos
/* Put (ones-1) 1s on the right by doing the following:
* (1) Shift 1 over by (ones-1) spots. If ones = 3, this gets you 0..0100
* (2) Subtract one from that to get 0..0011
* (3) OR with n
*/
n |= (1 << (c1 - 1)) - 1;
return n;
}
public static int getNextArith(int n) {
int c = n;
int c0 = 0;
int c1 = 0;
while (((c & 1) == 0) && (c != 0)) {
c0++;
c >>= 1;
}
while ((c & 1) == 1) {
c1++;
c >>= 1;
}
/* If c is 0, then n is a sequence of 1s followed by a sequence of 0s. This is already the biggest
* number with c1 ones. Return error.
*/
if (c0 + c1 == 31 || c0 + c1 == 0) {
return -1;
}
/* Arithmetically:
* 2^c0 = 1 << c0
* 2^(c1-1) = 1 << (c0 - 1)
* next = n + 2^c0 + 2^(c1-1) - 1;
*/
return n + (1 << c0) + (1 << (c1 - 1)) - 1;
}
public static int getPrev(int n) {
int temp = n;
int c0 = 0;
int c1 = 0;
while ((temp & 1) == 1) {
c1++;
temp >>= 1;
}
/* If temp is 0, then the number is a sequence of 0s followed by a sequence of 1s. This is already
* the smallest number with c1 ones. Return -1 for an error.
*/
if (temp == 0) {
return -1;
}
while (((temp & 1) == 0) && (temp != 0)) {
c0++;
temp >>= 1;
}
int p = c0 + c1; // position of right-most non-trailing one (where the right most bit is bit 0)
/* Flip right-most non-trailing one.
* Example: n = 00011100011.
* c1 = 2
* c0 = 3
* pos = 5
*
* Build up a mask as follows:
* (1) ~0 will be a sequence of 1s
* (2) shifting left by p + 1 will give you 11.111000000 (six 0s)
* (3) ANDing with n will clear the last 6 bits
* n is now 00011000000
*/
n &= ((~0) << (p + 1)); // clears from bit p onwards (to the right)
/* Create a sequence of (c1+1) 1s as follows
* (1) Shift 1 to the left (c1+1) times. If c1 is 2, this will give you 0..001000
* (2) Subtract one from that. This will give you 0..00111
*/
int mask = (1 << (c1 + 1)) - 1; // Sequence of (c1+1) ones
/* Move the ones to be right up next to bit p
* Since this is a sequence of (c1+1) ones, and p = c1 + c0, we just need to
* shift this over by (c0-1) spots.
* If c0 = 3 and c1 = 2, then this will look like 00...0011100
*
* Then, finally, we OR this with n.
*/
n |= mask << (c0 - 1);
return n;
}
public static int getPrevArith(int n) {
int temp = n;
int c0 = 0;
int c1 = 0;
while (((temp & 1) == 1) && (temp != 0)) {
c1++;
temp >>= 1;
}
/* If temp is 0, then the number is a sequence of 0s followed by a sequence of 1s. This is already
* the smallest number with c1 ones. Return -1 for an error.
*/
if (temp == 0) {
return -1;
}
while ((temp & 1) == 0 && (temp != 0)) {
c0++;
temp >>= 1;
}
/* Arithmetic:
* 2^c1 = 1 << c1
* 2^(c0 - 1) = 1 << (c0 - 1)
*/
return n - (1 << c1) - (1 << (c0 - 1)) + 1;
}
public static void binPrint(int i) {
System.out.println(i + ": " + Integer.toBinaryString(i));
}
public static void main(String[] args) {
for (int i = 0; i < 200; i++) {
int p1 = getPrevSlow(i);
int p2 = getPrev(i);
int p3 = getPrevArith(i);
int n1 = getNextSlow(i);
int n2 = getNext(i);
int n3 = getNextArith(i);
if (p1 != p2 || p2 != p3 || n1 != n2 || n2 != n3) {
binPrint(i);
binPrint(p1);
binPrint(p2);
binPrint(p3);
binPrint(n1);
binPrint(n2);
binPrint(n3);
System.out.println("");
}
}
System.out.println("Done!");
}
}